import { ccs } from "../services";
import { TouchExtend } from "../TouchExd";
import { touchExd } from "../TouchExtend";
import { ListItem } from "./ListItem";

const { ccclass, property, executeInEditMode, requireComponent, menu } = cc._decorator;

export const EListLayoutType = cc.Enum({
  Horizontal: 0,
  Vertical: 1,
});

const testBgNodeName = "list_view_test_bg";

/**
 * 用完要删除测试节点 list_view_test_bg 以及勾掉 _isTest 选项
 */
@ccclass
@executeInEditMode
@requireComponent(cc.ScrollView)
@menu("adapter/ListViewAdapter")
export class ListViewAdapter extends cc.Component {
  @property({type: cc.Component.EventHandler, tooltip: '元素节点刷新的回调函数'})
  cellEvent: cc.Component.EventHandler = null;

  @property
  private _layoutType = EListLayoutType.Vertical;

  @property({ type: EListLayoutType, tooltip: "布局方式：水平或者上下" })
  get layoutType() {
    return this._layoutType;
  }
  set layoutType(value: number) {
    this._layoutType = value;
    this.initAnchorPoint();
    this.updateLayout();
    let scrollview = this.getComponent(cc.ScrollView);
    scrollview.vertical = value == EListLayoutType.Vertical;
    scrollview.horizontal = !scrollview.vertical;
    this._widgetSize.width = 0;
  }

  @property(cc.Prefab)
  _cellPre: cc.Prefab = null;

  @property({ type: cc.Prefab, tooltip: "元素节点的预制" })
  get cellPre() {
    return this._cellPre;
  }
  set cellPre(value: cc.Prefab) {
    this._cellPre = value;
    this.updateLayout();
  }

  @property
  private _spacingX: number = 0;

  @property({
    type: cc.Float,
    tooltip: "横向间隔",
    visible() {
      return this._gridNum > 1 || this.layoutType == EListLayoutType.Horizontal;
    },
  })
  get spacingX() {
    return this._spacingX;
  }
  set spacingX(value: number) {
    this._spacingX = value;
    this.updateLayout();
  }

  @property
  private _spacingY: number = 0;
  
  @property({
    type: cc.Float,
    tooltip: "纵向间隔",
    visible() {
      return this._gridNum > 1 || this.layoutType == EListLayoutType.Vertical;
    },
  })
  get spacingY() {
    return this._spacingY;
  }
  set spacingY(value: number) {
    this._spacingY = value;
    this.updateLayout();
  }

  @property
  private _gridNum: number = 1;
  @property({ type: cc.Float, tooltip: "每行或者每列的子节点数量" })
  get gridNum() {
    return this._gridNum;
  }
  set gridNum(value: number) {
    this._gridNum = value;
    this.updateLayout();
  }
  private svBBoxRect: cc.Rect = null; //盒子的碰撞检测区域
  private _showNeedNum: number = 0; // 需要显示的子节点数
  private _widgetSize: cc.Size = cc.size(0, 0);

  public dataList: Array<Object> = [];
  private _widget: cc.Widget = null;
  private _layoutCpt: cc.Layout = null;
  private _idleNodes: cc.Node[] = []; // 闲置的节点 用来重复利用

  // 分帧加载参数
  private _isStartLoading: boolean = false;
  private _curLoadIdx: number = 0;

  @property({ tooltip: "是否开启分帧加载" })
  isFrameLoading: boolean = true;
  @property({
    tooltip: "每帧加载几个（默认 5个）",
    visible() {
      return this.isFrameLoading;
    },
  })
  loadNum: number = 5;

  //编辑器内测试属性
  @property({ tooltip: "仅供编辑器测试" })
  testNum: number = 2;

  private _isTest: boolean = false;
  @property({ tooltip: "重新刷新, 仅供编辑器测试" })
  get isTest() {
    return this._isTest;
  }
  set isTest(value: boolean) {
    this._isTest = value;
    this.test();
  }

  protected test() {
    let testData = [];
    for (let i = 0, len = this.testNum; i < len; i++) {
      testData.push(i);
    }
    if (this._isTest) {
      this.updateItems(testData, true);
    } else {
      this.node.getComponent(cc.ScrollView).content.destroyAllChildren();
    }
  }

  private isInit = false;

  onLoad() {
    let view = this.node.getChildByName("view");
    if (!view) {
      this.initListView();
    } else {
      this._widget = view.getComponent(cc.Widget);
      let content = this.getComponent(cc.ScrollView).content;
      this._layoutCpt = content.getComponent(cc.Layout);
      this.updateViewWidget();
    }
    this.calScrollBoxRect();//初始化内容区域
    // 分帧加载
    // this.executePreFrame(this.lazyLoad(this.testNum))
    this.isInit = true;
    
  }
  //清除内容
  clearAll() {
    this._curLoadIdx = 0;
    this.node.getComponent(cc.ScrollView).content.destroyAllChildren();
  }
  private initListView() {
    this.node.name = "ListView";
    this.node.width = 200;
    this.node.height = 200;

    let view = new cc.Node("view");
    view.parent = this.node;
    view.addComponent(cc.Mask);

    let content = new cc.Node("content");
    content.parent = view;
    //ccs.ui.utils.creatorSpiteSplash().parent = this.node;

   

    this._widget = view.addComponent(cc.Widget);

    this._layoutCpt = content.addComponent(cc.Layout);
    this._layoutCpt.verticalDirection = cc.Layout.VerticalDirection.TOP_TO_BOTTOM;
    this._layoutCpt.horizontalDirection = cc.Layout.HorizontalDirection.LEFT_TO_RIGHT;
    this._layoutCpt.resizeMode = cc.Layout.ResizeMode.CONTAINER;

    let scrollView = this.getComponent(cc.ScrollView);
    scrollView.content = content;
    scrollView.horizontal = false;
    scrollView.vertical = true;
    scrollView.inertia = false;
    scrollView.elastic = false;
    this.initAnchorPoint();
    this.updateViewWidget();
  }

  private initAnchorPoint() {
    if (this._layoutType == EListLayoutType.Vertical) {
      this.node.setAnchorPoint(0, 1);
      this._layoutCpt.node.setAnchorPoint(0.5, 1);
    } else {
      this.node.setAnchorPoint(0, 0);
      this._layoutCpt.node.setAnchorPoint(0, 0.5);
    }
  }

  // 刷新布局
  private updateLayout() {
    if (this._layoutCpt) {
      this._layoutCpt.spacingX = this._spacingX;
      this._layoutCpt.spacingY = this._spacingY;
      //if (this.isAutoLayout) {
      if (this._gridNum > 1) {
        this._layoutCpt.type = cc.Layout.Type.GRID;
        this._layoutCpt.startAxis =
          this._layoutType == EListLayoutType.Vertical
            ? cc.Layout.AxisDirection.HORIZONTAL
            : cc.Layout.AxisDirection.VERTICAL;
      } else {
        this._layoutCpt.type =
          this._layoutType == EListLayoutType.Vertical ? cc.Layout.Type.VERTICAL : cc.Layout.Type.HORIZONTAL;
      }
      if (this._layoutType == EListLayoutType.Vertical) {
        let width =
          this._gridNum * this.getCellWidth() +
          (this._gridNum - 1) * this._spacingX +
          this._layoutCpt.paddingLeft +
          this._layoutCpt.paddingRight;
        this._layoutCpt.node.width = width;
      } else {
        let height =
          this._gridNum * this.getCellHeight() +
          (this._gridNum - 1) * this._spacingY +
          this._layoutCpt.paddingTop +
          this._layoutCpt.paddingBottom;
        this._layoutCpt.node.height = height;
      }
      //}
    }
  }
  // 获取预制节点的宽
  private getCellWidth() {
    return this._cellPre
      ? this._cellPre.data.width * (this._layoutCpt.affectedByScale ? this._cellPre.data.scaleX : 1)
      : this.node.width / this._gridNum; //FIXME:
  }

  private getCellHeight() {
    return this._cellPre
      ? this._cellPre.data.height * (this._layoutCpt.affectedByScale ? this._cellPre.data.scaleY : 1)
      : this.node.height;
  }

  update(dt: number) {
    // if (this._isStartLoading) {
    //   let len = this.getAddItemCount(); //总数
    //   // loadNum 每次加载几个
    //   for (let i = 0; i < this.loadNum; i++) {
    //     let idx = this._curLoadIdx + i;
    //     if (idx < len) {
    //       this.addItem(idx);
    //     } else {
    //       // 加载结束
    //      
    //       break;
    //     }
    //   }
    //   this._curLoadIdx += this.loadNum;
    // }
  }

  lateUpdate() {
    if (CC_EDITOR) {
      if (this._widget.node.height != this._widgetSize.height || this._widget.node.width != this._widgetSize.width) {
        if (this._layoutType == EListLayoutType.Vertical) {
          this._layoutCpt.node.y = this._widget.node.height * 0.5;
          // this._layoutCpt.node.x = 0;
        } else {
          this._layoutCpt.node.x = -this._widget.node.width * 0.5;
          // this._layoutCpt.node.y = 0;
        }

        this._widgetSize.height = this._widget.node.height;
        this._widgetSize.width = this._widget.node.width;
      }
    }
  }

  updateItems<ItemData>(list: ItemData[], isTest = false) {
    if (!this.isInit) {
      this.onLoad();
    }

    if (list?.length <= 0) {
      return;
    }
    this.dataList = list;
    if (isTest) {
      for (let i = 0, len = this.getAddItemCount(); i < len; i++) {
        this.addItem(i, isTest);
      }
      return;
    }
    console.log('changeType')
    if (this.isFrameLoading) {
      // this._isStartLoading = true; //是否加载中
      this._curLoadIdx = 0;
      this.executePreFrame(this.lazyLoad(list.length));
    } else {
      for (let i = 0, len = this.getAddItemCount(); i < len; i++) {
        this.addItem(i);
      }
      this.loadEnd();
    }
  }

  // 加载结束回调
  private loadEnd() {
    this._isStartLoading = false;
    //sd.pf.doEventCallback(this.endEvent);
    let idx = this.getAddItemCount();//需要的数量
    let childCount = this._layoutCpt.node.childrenCount;//子节点数量
    while (idx < childCount) {
      let child = this._layoutCpt.node.children[idx];
      child.removeFromParent(false);
      this._idleNodes.push(child);
      childCount--;
    }
  }

  setNeedShowNum(value: number) {
    if (this._showNeedNum != value) {
      this._showNeedNum = value;
      return true;
    }
    return false;
  }

  setNeedShowNumFull(value: number) {
    return this.setNeedShowNum(Math.ceil(value / this.gridNum) * this.gridNum);
  }

  private getAddItemCount() {
    return this._showNeedNum > 0 ? this._showNeedNum : this.dataList.length;
  }

  private updateViewWidget() {
    if (this._widget) {
      this._widget.top = 0; //this._top;
      this._widget.bottom = 0; //this._bottom;
      this._widget.left = 0; //this._left;
      this._widget.right = 0; //this._right;
      this.updateLayout();
    }
  }

  addItem(idx: number, isTest = false) {
    if (!this._cellPre) {
      return;
    }
    let item = this._layoutCpt.node.children[idx];
    if (!item ) {
      console.log('=====================list')
      if (this._idleNodes.length > 0) {
        //重复利用节点
        item = this._idleNodes.pop();
      } else {
        item = cc.instantiate(this._cellPre);
        if (!isTest) {
          TouchExtend.touchEvent(item, cc.Node.EventType.TOUCH_END, () => {
            itemScript.onItemclick(this.dataList[idx]);
          })
          if (this._layoutCpt.type == cc.Layout.Type.GRID) {
            item.setAnchorPoint(0.5, 0.5);
          }
          item.setPosition(0, 0); // 坐标强制设置为0 0 布局问题
        }
      }
      const itemScript = item.getComponent(ListItem);
      if (!itemScript) {
        console.error(`item must being script ${ListItem}`);
      }
      itemScript._initItem(this.dataList[idx], idx);
      this._layoutCpt.node.addChild(item);
    } else {
      if (!isTest) {
        const itemScript = item.getComponent(ListItem);
        itemScript._initItem(this.dataList[idx], idx);
      }
    }
    item.active = true;
    ccs.gf.doEventCallback( this.cellEvent, item, this.dataList[idx], idx)

  }
  // 可视区域优化
  calScrollBoxRect() {
    let scrollView = this.getComponent(cc.ScrollView);
    let svLeftBottomPoint = scrollView.node.parent.convertToWorldSpaceAR(
      cc.v2(
        scrollView.node.x - scrollView.node.anchorX * scrollView.node.width,
        scrollView.node.y - scrollView.node.anchorY * scrollView.node.height
      )
    );
    
    // 求出 ScrollView 可视区域在世界坐标系中的矩形（碰撞盒）
    this.svBBoxRect = cc.rect(
      svLeftBottomPoint.x,
      svLeftBottomPoint.y,
      scrollView.node.width,
      scrollView.node.height
    );
  }
  handlerScroll() {
    // cc.log(this.svBBoxRect);
    // 遍历 ScrollView Content 内容节点的子节点
    let scrollView = this.getComponent(cc.ScrollView);
    scrollView.content.children.forEach((childNode: cc.Node) => {
      let itemComponent = childNode.getComponent(ListItem);
      // 对每个子节点的包围盒做和 ScrollView 可视区域包围盒做碰撞判断
      // 如果相交了，那么就显示，否则就隐藏
      // cc.log(childNode.getBoundingBoxToWorld());
      if (childNode.getBoundingBoxToWorld().intersects(this.svBBoxRect)) {
          if (childNode.opacity != 255) {
            itemComponent.setEnter(255);
          }
      } else {
          if (childNode.opacity != 0) {
            itemComponent.setEnter(0);
          }
      }
    });
  }
  //分段执行的函数，每次从当前加载的数量开始，初始为0
  *lazyLoad(length: number) {
      for (let i = this._curLoadIdx; i < length; i++) {
        yield this.addItem(i);
      }
  }
  // 分帧加载函数
  executePreFrame(gen: Generator) {
    return new Promise((resolve, reject) => {
        let count = 0;
        let excute = () => {
          //分段执行
          for(let res = gen.next(); ; res = gen.next()){
            count ++;
            this._curLoadIdx ++;
            //是否执行完毕
            if(res.done || res == null) {
              this.loadEnd();
              resolve(true);
              return;
            }
            //如果当前超过了设置的加载数量，则移到下一帧中加载
            if(count > this.loadNum) {
              this.scheduleOnce(() => {
                count = 0;
                excute();
              })
              return ;
            }
          }
        }
        excute();
    })
  }
}
